
package atm.components;

import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import atm.model.Tray;
import atm.model.Trays;

import com.google.gson.Gson;

/**
 * Provides access to cash dispenser database.
 */
public class CashDispenserDb {

	private Gson gson;

	private final String dbPath = "res\\cashDispenserDb.json";

	private Trays trays;

	public CashDispenserDb() {
		gson = new Gson();

		try {
			FileReader fr = new FileReader(new File(dbPath));
			setTrays(gson.fromJson(fr, Trays.class));
			fr.close();
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	public List<Tray> availableBills() {
		if (getTrays() != null && getTrays().getTrays() != null && getTrays().getTrays().size() > 0) {

			List<Tray> filteredTrays = new ArrayList<Tray>();

			for (Tray tray : getTrays().getTrays()) {
				if (tray.getBillCount() > 0) {
					filteredTrays.add(tray);
				}
			}

			Collections.sort(filteredTrays, new Comparator<Tray>() {

				@Override
				public int compare(Tray o1, Tray o2) {
					if (o1.getBillDenomination() != o2.getBillDenomination()) {
						return o1.getBillDenomination() - o2.getBillDenomination();
					} else {
						return o1.getBillCount() - o2.getBillCount();
					}
				}
			});

			return filteredTrays;
		}
		throw new RuntimeException();
	}

	public Trays getTrays() {
		return trays;
	}

	private void setTrays(Trays value) {
		trays = value;
	}

	public boolean subtractBills(List<Integer> usedBills) {
		if (getTrays() != null && getTrays().getTrays() != null && getTrays().getTrays().size() > 0 && usedBills != null) {
			return subtractBills(usedBills, 1);
		}
		return false;
	}

	public boolean subtractBills(List<Integer> usedBills, int amount) {
		if (getTrays() != null && getTrays().getTrays() != null && getTrays().getTrays().size() > 0 && amount > 0 && usedBills != null) {

			for (Integer denomination : usedBills) {
				for (Tray tray : getTrays().getTrays()) {
					if (tray.getBillDenomination() == denomination && tray.getBillCount() >= amount) {
						tray.setBillCount(tray.getBillCount() - amount);
						break;
					}
				}
			}

			synchronize();
			return true;
		}
		return false;
	}

	private synchronized void synchronize() {
		String json = gson.toJson(getTrays());
		FileWriter fw;
		try {
			fw = new FileWriter(new File(dbPath));
			fw.write(json);
			fw.close();
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}
}
